package com.ruoyi.common.utils.excel;

import com.alibaba.excel.EasyExcel;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;

import java.io.Serial;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;

/**
 * Excel通用导出工具类
 *
 * @param <T>
 * @author liuzhexian
 */
public class ExcelUtils<T> implements Serializable {

    protected final Logger log = LoggerFactory.getLogger(this.getClass());

    @Serial
    private static final long serialVersionUID = 5L;

    /**
     * 实体对象
     */
    public Class<T> clazz;

    public ExcelUtils(Class<T> clazz) {
        this.clazz = clazz;
    }

    /**
     * 通用导出方法
     *
     * @param response response
     * @param list     导出的列表
     * @param title    导出的名称
     */
    public void exportData(HttpServletResponse response, List<T> list, String title) {
        // 无法通过@Value注入，只好使用SpringUtil.getBean手动获取
        Environment env = SpringUtils.getBean(Environment.class);
        // 配置中的参数只能读取到字符串
        String showWatermark = env.getProperty("export.show-watermark");
        // 根据字符串判断导出是否需要带水印
        if (Boolean.getBoolean(showWatermark)) {
            exportSheetWithWatermark(response, list, title);
        } else {
            exportSheetWithoutWatermark(response, list, title);
        }
    }

    /**
     * 通用导出方法(无水印)
     *
     * @param response response
     * @param list     导出的列表
     * @param title    导出的名称
     */
    public void exportSheetWithoutWatermark(HttpServletResponse response, List<T> list, String title) {
        try {
            setHeaders(response, title);
            EasyExcel.write(response.getOutputStream(), this.clazz).sheet(title).doWrite(list);
        } catch (Exception e) {
            log.error("{}导出异常", title, e);
        }
    }


    /**
     * 通用导出方法(带水印)
     *
     * @param response   response
     * @param exportList 导出的列表
     * @param title      导出的名称
     */
    public void exportSheetWithWatermark(HttpServletResponse response, List<T> exportList, String title) {
        try {
            setHeaders(response, title);
            // 创建 ExcelWriter，并注册水印处理器
            Watermark watermark = new Watermark(String.format("%s %s", SecurityUtils.getLoginUser().getUser().getNickName(),DateUtils.dateTimeNow()));
//            // 一定要inMemory
            EasyExcel.write(response.getOutputStream(), this.clazz)
                    .inMemory(true).sheet(title).registerWriteHandler(new CustomWaterMarkHandler(watermark)).doWrite(exportList);
        } catch (Exception e) {
            log.error("{}导出异常", title, e);
        }
    }

    /**
     * 设置response的header和导出的文件名
     *
     * @param response
     * @param title
     * @throws UnsupportedEncodingException
     */
    public void setHeaders(HttpServletResponse response, String title) throws UnsupportedEncodingException {
        title = title + "-" + DateUtils.parseDateToStr("yyyyMMddHHmmss",new Date());
        // 这个 MIME 类型用于指示返回的文件扩展名通常是.xlsx
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        //建议加上该段，否则可能会出现前端无法获取Content-disposition
        response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "Content-Disposition");
        // 这里URLEncoder.encode可以防止中文乱码
        String fileName = URLEncoder.encode(title, StandardCharsets.UTF_8).replace("+", "%20");
        response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + fileName + ".xlsx");
    }

}
